from sqlmodel import Session, select, and_, or_, func
from typing import Optional
import models
import utility
from common import exception
from datetime import datetime
from dependencies import engine, SessionDep

"""查询角色及其关联菜单列表数据

Keyword arguments:
skip -- 起始页 (default 0)
limit -- 每页条数 (default 20)
name -- 角色名称 (default None)
code -- 角色编码 (default None)
Return: result -- 角色列表数据
"""


def get_role(
    skip: int = 0,
    limit: Optional[int] = 20,
    name: str | None = None,
    code: str | None = None,
    is_active: bool | None = None,
    user: models.SystemUser = None,
    session: SessionDep = Session(engine),
):

    # 查询条件
    conditions = [
        models.SystemRole.name.like(f"%{name}%") if name else True,
        models.SystemRole.code == code if code is not None else True,
        models.SystemRole.is_active == is_active if is_active is not None else True,
    ]

    if limit:
        # 查询语句
        statement = (
            select(models.SystemRole)
            .filter(and_(*conditions))
            .order_by(models.SystemRole.updatetime.desc())
            .offset(skip)
            .limit(limit)
        )
    else:
        # 获取所有角色数据
        statement = select(models.SystemRole)

    # 执行查询
    items = session.exec(statement).all()
    

    # 查询总条数
    total_statement = (
        select(func.count()).select_from(
            models.SystemRole).filter(and_(*conditions))
    )
    total = session.exec(total_statement).one()  # 使用 one() 方法获取单个标量结果

    # 初始系统角色数据
    system_role = []

    for item in items:
        # 查询角色关联的菜单数据
        rolelinkmenus = session.exec(
            select(models.SystemRoleMenuLink).where(
                models.SystemRoleMenuLink.role_id == item.id)
        ).all()

        # 提取菜单ID
        menu_ids = [rolelinkmenu.menu_id for rolelinkmenu in rolelinkmenus]

        # 将SQLModel对象转换为字典
        item = dict(item)

        # 将创建人和更新人的ID转换为姓名
        item["creator"] = session.get(
            models.SystemUser, item["create_id"]).name
        item["updater"] = session.get(
            models.SystemUser, item["update_id"]).name

        # 将菜单列表添加到角色列表中
        item["menu_ids"] = menu_ids

        system_role.append(item)

    return system_role, total


"""新增角色及其关联菜单数据

Keyword arguments:
role -- 新增角色参数
Return: system_role -- 新增角色数据
"""


def create_role(
    role: models.SystemRoleCreate,
    user: models.SystemUser = None,
    session: SessionDep = Session(engine),
):
    # 新增角色数据
    system_role = models.SystemRole(
        **dict(role),
        create_id=user.id,
        update_id=user.id,
        createtime=datetime.now(),
        updatetime=datetime.now(),
    )
    session.add(system_role)
    session.commit()
    session.refresh(system_role)

    # 新增角色菜单数据
    for menu_id in role.menu_ids:
        # 查询菜单数据
        menu = session.get(models.SystemMenu, menu_id)
        # 校验菜单是否存在
        if not menu or menu.is_active == False:
            raise exception.create_http_exception(
                status_code=404, detail="角色关联的菜单不存在"
            )
        # 新增角色菜单数据
        system_role_menu_link = models.SystemRoleMenuLink(
            role_id=system_role.id,
            menu_id=menu_id,
        )
        session.add(system_role_menu_link)
        session.commit()
        session.refresh(system_role_menu_link)
    return system_role


"""编辑角色及其关联的数据

Keyword arguments:
argument -- description
Return: return_description
"""


def update_role(
    id: int,
    role: models.SystemRoleUpdate,
    user: models.SystemUser = None,
    session: SessionDep = Session(engine),
):
    # 查询系统角色数据
    system_role = session.get(models.SystemRole, id)
    # 校验角色是否存在
    if not system_role:
        raise exception.create_http_exception(status_code=404, detail="角色不存在")

    # 更新角色信息
    for key, value in dict(role).items():
        if key != "menu_ids":
            setattr(system_role, key, value)

    # 更新更新人id和更新时间数据
    system_role.update_id = user.id
    system_role.updatetime = datetime.now()
    session.commit()
    session.refresh(system_role)

    # 查询当前角色已关联的菜单
    has_rolemenuelinks = session.exec(
        select(models.SystemRoleMenuLink).where(models.SystemRoleMenuLink.role_id == id)
    ).all()

    # 提取已关联的菜单id
    orginal_menu_ids = [rolemenu.menu_id for rolemenu in has_rolemenuelinks]

    # 新增角色菜单数据
    for menu_id in role.menu_ids:
        if menu_id not in orginal_menu_ids:
            # 查询菜单数据
            menu = session.get(models.SystemMenu, menu_id)
            # 校验菜单是否存在
            if not menu or menu.is_active == False:
                raise exception.create_http_exception(
                    status_code=404, detail="角色关联的菜单不存在"
                )
            # 新增角色菜单数据
            system_role_menu_link = models.SystemRoleMenuLink(
                role_id=system_role.id,
                menu_id=menu_id,
            )
            session.add(system_role_menu_link)
            session.commit()
            session.refresh(system_role_menu_link)

    # 删除不需要的菜单关联
    for menu_id in orginal_menu_ids:
        if menu_id not in role.menu_ids:
            # 删除角色菜单数据
            system_role_menu_link = session.exec(
                select(models.SystemRoleMenuLink).where(
                    models.SystemRoleMenuLink.role_id == id,
                    models.SystemRoleMenuLink.menu_id == menu_id,
                )
            ).one()
            session.delete(system_role_menu_link)
            session.commit()

    return system_role


"""删除角色数据

Keyword arguments:
id -- 角色id
Return: None
"""


def delete_role(
    id: int, user: models.SystemUser, session: Optional[SessionDep] = Session(engine)
):
    # 查询角色数据
    system_role = session.get(models.SystemRole, id)
    # 如果角色数据不存在，则抛出异常
    if not system_role:
        raise exception.create_http_exception(status_code=404, detail="角色不存在,id为%s" % id)
    # 删除角色数据
    session.delete(system_role)
    session.commit()
    return system_role
